#pragma once

#include "Math/Math.h"
#include <vector>
#include <string>

#define HALTON_SAMPLES 16

struct OpaqueObject
{
	uint32 pad;
};

struct MaterialGpu {

	glm::vec4 albedo;
	glm::vec4 emissive;
	glm::vec4 roughnessMetallic;

	MaterialGpu()
	{
		albedo = glm::vec4(0.f);
		emissive = glm::vec4(0.f);
		roughnessMetallic = glm::vec4(0.f);
	}
};

struct VertexGpu
{
	glm::vec3 position;
	glm::vec3 normal;
	glm::vec3 tangent;
	glm::vec2 uv;
};

struct GBufferPushConstants
{
	glm::mat4 model;
	glm::mat4 prevModel;
	uint32 objectIndex;
	float roughnessMultiplier;
};

struct ObjectDescGpu
{
	uint64 vertexAddress;
	uint64 indexAddress;
};

enum LightType
{
	LIGHT_TYPE_DIRECTIONAL,
	LIGHT_TYPE_POINT,
	LIGHT_TYPE_SPOT,
	LIGHT_TYPE_COUNT
};

struct Light
{
	glm::vec4 data0;
	glm::vec4 data1;
	glm::vec4 data2;
	glm::vec4 data3;

	void SetDirection(glm::vec3 value)
	{
		data0.x = value.x;
		data0.y = value.y;
		data0.z = value.z;
	}

	void SetPosition(glm::vec3 value)
	{
		data1.x = value.x;
		data1.y = value.y;
		data1.z = value.z;
	}

	void SetColor(glm::vec3 value)
	{
		data2.x = value.x;
		data2.y = value.y;
		data2.z = value.z;
	}

	void SetIntensity(float value)
	{
		data0.w = value;
	}

	void SetRadius(float value)
	{
		data1.w = value;
	}

	void SetType(LightType value)
	{
		data3.x = value;
	}

	void SetCosThetaOuter(float value)
	{
		data3.y = value;
	}

	void SetCosThetaInner(float value)
	{
		data3.z = value;
	}
};

struct PerFrameUbo
{
	__declspec(align(16))
		glm::mat4 viewInverse;
	__declspec(align(16))
		glm::mat4 projInverse;
	__declspec(align(16))
		glm::mat4 projViewInverse;
	__declspec(align(16))
		glm::mat4 prevProjView;
	__declspec(align(16))
		glm::mat4 projView;
	__declspec(align(16))
		glm::vec4 cameraPosition;
	__declspec(align(16))
		glm::vec4 currentPrevJitter;
	__declspec(align(16))
		Light light;
};

struct DDGIUniforms
{
	glm::vec3 gridStartPosition;
	glm::vec3 gridStep;
	glm::ivec3 probeCounts;
	float maxDistance;
	float depthSharpness;
	float hysteresis;
	float normalBias;
	float energyPreservation;
	int32 irradianceProbeSideLength;
	int32 irradianceTextureWidth;
	int32 irradianceTextureHeight;
	int32 depthProbeSideLength;
	int32 depthTextureWidth;
	int32 depthTextureHeight;
	int32 raysPerProbe;
	int32 visibilityTest;
};

float HaltonSequence(int base, int index);

float RadicalInverseVdc(uint32 bits);

glm::vec2 Hammersley(uint32 i, uint32 N);